#ifndef IMPLEMENTATION_HPP
#define IMPLEMENTATION_HPP
#include "implementation.h"

template <typename Range>
bool focus_group<Range>::focused_in_range() const noexcept
{
	using std::end;
	return focused_element != end(elements);
}

template <typename Range>
bool focus_group<Range>::focus() const noexcept
{
	using std::end;
	using ::focus;
	return focused_in_range() &&
		focus(*focused_element);
}

template <typename Range>
void focus_group<Range>::drop_focus() noexcept
{
	using std::end;
	using ::drop_focus;
	if( focused_in_range() )
		drop_focus(*focused_element);
}

template <typename Range>
bool focus_group<Range>::focus_on(const i_focusable& target) noexcept
{
	using std::begin;
	using std::end;
	using ::drop_focus;
	using ::focus_on;

	if(focused_in_range())
		drop_focus(*focused_element);

	auto focused = std::find_if(begin(elements), end(elements),
		[&target](auto& x) {return focus_on(x,target);});

	if(focused != end(elements))
	{
		focused_element = focused;
		return true;
	}
	else return false;
}

template <typename Range>
bool focus_group<Range>::focus(direction dir)
{
	using std::begin;
	using std::end;
	using ::focus;
	using ::drop_focus;

	bool forward = dir >= 0;

	if(!this->focus())
	{
		focused_element = forward
			? begin(elements)
			: end(elements) - 1
		;
		focus(*focused_element, dir);
		return true;
	}

	if(focus(*focused_element, dir))
		return true;

	if(forward
		? focused_element + dir != end(elements)
		: focused_element != begin(elements))
	{
		drop_focus(*focused_element);
		focused_element += dir;
		focus(*focused_element, dir);
		return true;
	}

	return false;
}

template <typename Range>
focus_group<Range>::focus_group(Range range) :
	elements(std::move(range)),
	focused_element(std::end(elements))
{}

template <typename Range>
focus_group<Range>::focus_group() :
	elements(),
	focused_element(std::end(elements))
{}

#endif /* end of include guard */
